<?php
declare (strict_types = 1);

namespace app\admin\model\project;

use bbweb\traits\ModelTrait;
use bbweb\basic\BaseModel;

/**
 * @mixin \think\Model
 */
class ProWorkdays extends BaseModel
{
    /**
     * 数据表主键
     * @var string
     */
    protected $pk = 'id';

    /**
     * 模型名称
     * @var string
     */
    protected $name = 'workdays';

    const WEEK_WORKING_DAY = [1, 2, 3, 4, 5,0];
    const ON_DUTY_TIME = '8:30:00';//早上上班
    const END_WU_TIME = '12:00:00';//中午下班
    const START_WU_TIME = '13:00:00';//下午上班
    const OFF_DUTY_TIME = '17:30:00';//下午下班

    //每天工作时长
    const ONE_DAY_HOURS = 8;

    use ModelTrait;


    // 设置字段信息
    protected $schema = [
        'id'			=> 'int',
        'day'			=> 'int',
        'type'		    => 'tinyint',
    ];

    /**
     * @param int $time
     * @param int $type 1:工作日0:休息日
     * @return array
     */
    public static function getWorkingDays(int $time, int $type = 0)
    {
        return $days = self::where('day', '>', $time)->where('type',$type)->column('day','id');
    }

    /**
     * @param int $start_time
     * @param int $over_time
     * @return float|int
     */
    public static function getWorkingHours(int $start_time, int $over_time)
    {
        // 如果工作日列表为空 返回0
        $workingDays = self::workingDays($start_time, $over_time);
        //var_dump($workingDays);
        if (empty($workingDays)) {
            return 0;
        }
        $x_time = 0;//每次不足一天的时候中午休班的时间差
        //开始那天的上班时间戳
        $on_duty_time = strtotime(date('Y/m/d', $start_time) . ' ' . self::ON_DUTY_TIME);
        //开始那天的中午下班时间
        $on_duty_time_up = strtotime(date('Y/m/d', $start_time) . ' ' . self::END_WU_TIME);
        //开始那天的下午上班时间
        $on_duty_time_down = strtotime(date('Y/m/d', $start_time) . ' ' . self::START_WU_TIME);
        //结束那天的下班时间戳
        $off_duty_time = strtotime(date('Y/m/d', $over_time) . ' ' . self::OFF_DUTY_TIME);
        //结束那天的中午下班时间
        $off_duty_time_up = strtotime(date('Y/m/d', $over_time) . ' ' . self::END_WU_TIME);
        //结束那天的下午上班时间
        $off_duty_time_down = strtotime(date('Y/m/d', $over_time) . ' ' . self::START_WU_TIME);
        //如果开始时间小于当天上班时间调整为上班时间
        if ($start_time < $on_duty_time && $over_time > $on_duty_time) {
            $start_time = $on_duty_time;
        }
        //如果截止时间大于当天下班时间调整为下班时间
        if ($over_time > $off_duty_time && $start_time < $off_duty_time) {
            $over_time = $off_duty_time;
        }
        //如果开始时间在中午时间段则调整为中午上班时间
        if ( $start_time > $on_duty_time_up && $start_time < $on_duty_time_down ) {
            $start_time = $on_duty_time_down;
        }
        //如果结束时间在中午时间段则调整为中午下班时间
        if( $over_time > $off_duty_time_up && $over_time < $off_duty_time_down ) {
            $over_time = $off_duty_time_up;
        }
        if($start_time < $on_duty_time_up && $over_time > $off_duty_time_down ) {
            $x_time = 3600;
        }
        // 如果开始时间不是工作日,将开始时间调整为第一个工作日的上班时间
        if (!in_array(date('Y/m/d', $start_time), $workingDays)) {
            $start_time = strtotime($workingDays[0] . ' ' . self::ON_DUTY_TIME);
        }
        // 如果截止时间不是工作日,将截止时间调整为最后一个工作日的下班时间
        if (!in_array(date('Y/m/d', $over_time), $workingDays)) {
            $over_time = strtotime(end($workingDays) . ' ' . self::OFF_DUTY_TIME);
        }

        // 如果开始时间与截止时间是同一天,直接计算
        if (date('Y/m/d', $start_time) == date('Y/m/d', $over_time)) {
            $sec = $over_time - $start_time;
            if ($sec > 3600 * self::ONE_DAY_HOURS) {
                $sec = 3600 * self::ONE_DAY_HOURS;
            }
            // 反之分别计算开始时间与截止时间
        } else {
            // 计算开始日工作时间
            $start_day_sec = strtotime($workingDays[0] . ' ' . self::OFF_DUTY_TIME) - $start_time;
            if ($start_day_sec > 3600 * self::ONE_DAY_HOURS) {
                $start_day_sec = 3600 * self::ONE_DAY_HOURS;
            }
            // 计算截止日工作时间
            $over_day_sec = $over_time - strtotime(end($workingDays) . ' ' . self::ON_DUTY_TIME);
            if ($over_day_sec > 3600 * self::ONE_DAY_HOURS) {
                $over_day_sec = 3600 * self::ONE_DAY_HOURS;
            }
            //去除开始和结束两天的满额工作时间
            $all_day_sec = ((count($workingDays) - 2) * self::ONE_DAY_HOURS) * 3600;
            $sec         = $start_day_sec + $over_day_sec + $all_day_sec;
        }

        return ceil(($sec - $x_time) / 3600 * 10) / 10;
    }

    /**
     * 计算工作日(包含开始与截止日期)
     * @param $start_time
     * @param $over_time
     * @return array
     */
    protected static function workingDays($start_time, $over_time)
    {
        //开始那天的下班时间
        $on_duty_time_up = strtotime(date('Y/m/d', $start_time) . ' ' . self::OFF_DUTY_TIME);
        if($start_time > $on_duty_time_up) {
            $start_time = strtotime('+1 day', $start_time);
        }

        $start_time = strtotime('-1 day', strtotime(date('Y/m/d', $start_time)));
        $over_time  = strtotime('-1 day', strtotime(date('Y/m/d', $over_time)));



        $new_workingDays = self::getWorkingDays($start_time, 1);//工作日
        $new_holidays    = self::getWorkingDays($start_time, 0);//休息日
        $workingDays     = [];

        while ($start_time <= $over_time) {
            $start_time     = strtotime('+1 day', $start_time);
            //判断是否常规工作日-预设休息日
            $is_holidays    = in_array(date('w', $start_time), self::WEEK_WORKING_DAY) && !in_array(strtotime(date('Y/m/d', $start_time)), $new_holidays);
            //判断是否为预设工作日
            $is_workingDays = in_array(strtotime(date('Y/m/d', $start_time)), $new_workingDays);

            if ($is_holidays || $is_workingDays) {
                $workingDays[] = date('Y/m/d', $start_time);
            }
        }

        return $workingDays;
    }
}
